﻿using HalconDotNet;
using MvCamCtrl.NET.CameraParams;
using MvCamCtrl.NET;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace CCSFPCLoaderUI.Services
{
    public class HIKCameraService : IHIKCameraService
    {
        private int nRet = MyCamera.MV_OK;
        public bool m_bIsDeviceOpen { get; set; }       // ch:设备打开状态 | en:Is device open
        public uint PayloadSize { get; set; }
        public ActionRef1<IntPtr, MyCamera.MV_FRAME_OUT_INFO_EX> ImageCallbackFunc { get; set; }
        public ConcurrentQueue<HObject> ImageQueue { get; set; }

        private MyCamera.cbOutputExdelegate ImageCallback;
        private MyCamera device = new MyCamera();
        public void CloseCamera()
        {
            try
            {
                // ch:停止抓图 | en:Stop grabbing
                nRet = device.MV_CC_StopGrabbing_NET();
                // ch:关闭设备 | en:Close device
                nRet = device.MV_CC_CloseDevice_NET();
                // ch:销毁设备 | en:Destroy device
                nRet = device.MV_CC_DestroyDevice_NET();
                m_bIsDeviceOpen = false;
            }
            catch { }
        }
        public bool OpenCamera(string cameraIP)
        {
            try
            {
                int nRet = MyCamera.MV_OK;

                // ch:枚举设备 | en:Enum deivce
                MyCamera.MV_CC_DEVICE_INFO_LIST stDevList = new MyCamera.MV_CC_DEVICE_INFO_LIST();
                nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref stDevList);
                if (MyCamera.MV_OK != nRet)
                {
                    Console.WriteLine("Enum device failed:{0:x8}", nRet);
                    return false;
                }
                Console.WriteLine("Enum device count :{0} \n", stDevList.nDeviceNum);
                if (0 == stDevList.nDeviceNum)
                {
                    return false;
                }

                MyCamera.MV_CC_DEVICE_INFO stDevInfo;

                Int32 nDevIndex = -1;
                // ch:打印设备信息 | en:Print device info
                for (Int32 i = 0; i < stDevList.nDeviceNum; i++)
                {
                    stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[i], typeof(MyCamera.MV_CC_DEVICE_INFO));

                    if (MyCamera.MV_GIGE_DEVICE == stDevInfo.nTLayerType)
                    {
                        MyCamera.MV_GIGE_DEVICE_INFO stGigEDeviceInfo = (MyCamera.MV_GIGE_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.stSpecialInfo.stGigEInfo, typeof(MyCamera.MV_GIGE_DEVICE_INFO));
                        uint nIp1 = ((stGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
                        uint nIp2 = ((stGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
                        uint nIp3 = ((stGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
                        uint nIp4 = (stGigEDeviceInfo.nCurrentIp & 0x000000ff);
                        if ($"{nIp1}.{nIp2}.{nIp3}.{nIp4}" == cameraIP)
                        {
                            nDevIndex = i;
                        }
                        Console.WriteLine("[device " + i.ToString() + "]:");
                        Console.WriteLine("DevIP:" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);
                        Console.WriteLine("ModelName:" + stGigEDeviceInfo.chModelName + "\n");
                    }
                    else if (MyCamera.MV_USB_DEVICE == stDevInfo.nTLayerType)
                    {
                        MyCamera.MV_USB3_DEVICE_INFO stUsb3DeviceInfo = (MyCamera.MV_USB3_DEVICE_INFO)MyCamera.ByteToStruct(stDevInfo.stSpecialInfo.stUsb3VInfo, typeof(MyCamera.MV_USB3_DEVICE_INFO));

                        if ($"{stUsb3DeviceInfo.chSerialNumber}" == cameraIP)
                        {
                            nDevIndex = i;
                        }

                        Console.WriteLine("[device " + i.ToString() + "]:");
                        Console.WriteLine("SerialNumber:" + stUsb3DeviceInfo.chSerialNumber);
                        Console.WriteLine("ModelName:" + stUsb3DeviceInfo.chModelName + "\n");
                    }
                }
                if (nDevIndex >= 0)
                {
                    stDevInfo = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(stDevList.pDeviceInfo[nDevIndex], typeof(MyCamera.MV_CC_DEVICE_INFO));

                    // ch:创建设备 | en: Create device
                    nRet = device.MV_CC_CreateDevice_NET(ref stDevInfo);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Console.WriteLine("Create device failed:{0:x8}", nRet);
                        return false;
                    }

                    // ch:打开设备 | en:Open device
                    nRet = device.MV_CC_OpenDevice_NET();
                    if (MyCamera.MV_OK != nRet)
                    {
                        Console.WriteLine("Open device failed:{0:x8}", nRet);
                        return false;
                    }

                    // ch:获取包大小 || en: Get Payload Size
                    MyCamera.MVCC_INTVALUE stParam = new MyCamera.MVCC_INTVALUE();
                    nRet = device.MV_CC_GetIntValue_NET("PayloadSize", ref stParam);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Console.WriteLine("Get PayloadSize Fail");
                        return false;
                    }
                    PayloadSize = stParam.nCurValue;

                    // ch:设置采集模式：连续
                    nRet = device.MV_CC_SetEnumValue_NET("AcquisitionMode", (uint)MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set AcquisitionMode failed:{0:x8}", nRet);
                        return false;
                    }
                    // ch:设置触发模式为on
                    nRet = device.MV_CC_SetEnumValue_NET("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set TriggerMode failed:{0:x8}", nRet);
                        return false;
                    }
                    // ch:设置触发源：line0
                    nRet = device.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set TriggerSource failed:{0:x8}", nRet);
                        return false;
                    }

                    //ch: 注册回调函数 | en:Register image callback
                    ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);
                    nRet = device.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                    if (MyCamera.MV_OK != nRet)
                    {
                        Console.WriteLine("Register image callback failed!");
                        return false;
                    }
                }
                else
                {
                    Debug.WriteLine($"未找到\"{cameraIP}\"设备");
                    return false;
                }

                m_bIsDeviceOpen = true;
                return true;
            }
            catch (HalconException ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }
        public Int32 ConvertToRGB(IntPtr pSrc, ushort nHeight, ushort nWidth, MyCamera.MvGvspPixelType nPixelType, IntPtr pDst)
        {
            if (IntPtr.Zero == pSrc || IntPtr.Zero == pDst)
            {
                return MyCamera.MV_E_PARAMETER;
            }

            int nRet = MyCamera.MV_OK;
            MyCamera.MV_CC_PIXEL_CONVERT_PARAM stPixelConvertParam = new MyCamera.MV_CC_PIXEL_CONVERT_PARAM();

            stPixelConvertParam.pSrcData = pSrc;//源数据
            if (IntPtr.Zero == stPixelConvertParam.pSrcData)
            {
                return -1;
            }

            stPixelConvertParam.nWidth = nWidth;//图像宽度
            stPixelConvertParam.nHeight = nHeight;//图像高度
            stPixelConvertParam.enSrcPixelType = nPixelType;//源数据的格式
            stPixelConvertParam.nSrcDataLen = (uint)(nWidth * nHeight * ((((uint)nPixelType) >> 16) & 0x00ff) >> 3);

            stPixelConvertParam.nDstBufferSize = (uint)(nWidth * nHeight * ((((uint)MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed) >> 16) & 0x00ff) >> 3);
            stPixelConvertParam.pDstBuffer = pDst;//转换后的数据
            stPixelConvertParam.enDstPixelType = MyCamera.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed;
            stPixelConvertParam.nDstBufferSize = (uint)nWidth * nHeight * 3;

            nRet = device.MV_CC_ConvertPixelType_NET(ref stPixelConvertParam);//格式转换
            if (MyCamera.MV_OK != nRet)
            {
                return -1;
            }

            return MyCamera.MV_OK;
        }

        public bool StartGrabe()
        {
            try
            {
                // ch:开启抓图 || en: start grab image
                nRet = device.MV_CC_StartGrabbing_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    Debug.WriteLine("Start grabbing failed:{0:x8}", nRet);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        public bool StopGrabe()
        {
            try
            {
                // ch:停止抓图 | en:Stop grabbing
                nRet = device.MV_CC_StopGrabbing_NET();
                if (MyCamera.MV_OK != nRet)
                {
                    Debug.WriteLine("Stop grabbing failed:{0:x8}", nRet);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        public bool SetTriggerMode(uint triggerMode)
        {
            // ch:设置触发模式为on
            nRet = device.MV_CC_SetEnumValue_NET("TriggerMode", triggerMode);
            if (MyCamera.MV_OK != nRet)
            {
                Debug.WriteLine("Set TriggerMode failed:{0:x8}", nRet);
                return false;
            }
            else
                return true;
        }
        public bool SetExposureTime(float time)
        {
            nRet = device.MV_CC_SetFloatValue_NET("ExposureTime", time);
            if (MyCamera.MV_OK != nRet)
            {
                Console.WriteLine("Set ExposureTime failed:{0:x8}", nRet);
                return false;
            }
            return true;
        }
        public bool SetFrameRate(float rate)
        {
            nRet = device.MV_CC_SetFloatValue_NET("AcquisitionFrameRate", rate);
            if (MyCamera.MV_OK != nRet)
            {
                Console.WriteLine("Set AcquisitionFrameRate failed:{0:x8}", nRet);
                return false;
            }
            return true;
        }
    }
}
